package com.example.smartcity

import android.annotation.SuppressLint
import android.content.ContentResolver
import android.content.ContentUris
import android.content.Context
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.os.storage.StorageManager
import android.provider.DocumentsContract
import android.provider.MediaStore
import android.provider.OpenableColumns
import android.text.TextUtils
import androidx.annotation.RequiresApi
import androidx.core.net.toFile
import java.io.File
import java.io.FileOutputStream
import java.lang.reflect.Array.get
import java.lang.reflect.Array.getLength


import kotlin.random.Random

fun uriToFile(context: Context, uri: Uri) =
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        uriToFileQ(context, uri)
    } else uriToFileN(context, uri)


@RequiresApi(Build.VERSION_CODES.Q)
private fun uriToFileQ(context: Context, uri: Uri): File? =
    if (uri.scheme == ContentResolver.SCHEME_FILE)
        uri.toFile()
    else if (uri.scheme == ContentResolver.SCHEME_CONTENT) {
        //把文件保存到沙盒
        val contentResolver = context.contentResolver
        val cursor = contentResolver.query(uri, null, null, null, null)
        cursor?.let {
            if (it.moveToFirst()) {
                val ois = context.contentResolver.openInputStream(uri)
                val displayName =
                    it.getString(it.getColumnIndex(OpenableColumns.DISPLAY_NAME))
                ois?.let {
                    File(
                        context.externalCacheDir!!.absolutePath,
                        "${Random.nextInt(0, 9999)}$displayName"
                    ).apply {
                        val fos = FileOutputStream(this)
                        android.os.FileUtils.copy(ois, fos)
                        fos.close()
                        it.close()
                    }
                }
            } else null

        }

    } else null

@SuppressLint("ServiceCast")
private fun uriToFileN(context: Context, uri: Uri): File? {
    val authority = uri.authority
    val scheme = uri.scheme
    val path = uri.path
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && path != null) {
        val externals = arrayOf("/external", "/external_path")
        externals.forEach {
            if (path.startsWith(it + "/")) {
                val file = File(
                    Environment.getExternalStorageDirectory().absolutePath + path.replace(it, "")
                )
                if (file.exists()) {
                    return file
                }
            }
        }
    }
    if (scheme == ContentResolver.SCHEME_FILE)
        return uri.toFile()
    else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(
            context,
            uri
        )
    ) {
        return if ("com.android.externalstorage.documents" == authority) {
            val docId = DocumentsContract.getDocumentId(uri)
            val split = docId.split(":").toTypedArray()
            val type = split[0]
            if ("primary".equals(type, ignoreCase = true)) {
                return File(
                    Environment.getExternalStorageDirectory()
                        .toString() + "/" + split[1]
                )
            } else {
                val mStorageManager =
                    context.getSystemService(Context.STORAGE_SERVICE) as StorageManager
                val storageVolumeClazz = Class.forName("android.os.storage.StorageVolume")
                val getVolumeList = mStorageManager.javaClass.getMethod("getVolumeList")
                val getUuid = storageVolumeClazz.getMethod("getUuid")
                val getState = storageVolumeClazz.getMethod("getState")
                val getPath = storageVolumeClazz.getMethod("getPath")
                val isPrimary = storageVolumeClazz.getMethod("isPrimary")
                val isEmulated = storageVolumeClazz.getMethod("isEmulated")
                val result = getVolumeList.invoke(mStorageManager)
                val length = getLength(result)
                for (i in 0 until length) {
                    val storageVolumeElement = get(result, i)
                    val mounted = Environment.MEDIA_MOUNTED == getState.invoke(storageVolumeElement)
                            || Environment.MEDIA_MOUNTED_READ_ONLY == getState.invoke(
                        storageVolumeElement
                    )

                    if (!mounted) continue
                    if (isPrimary.invoke(storageVolumeElement) as Boolean
                        && isEmulated.invoke(storageVolumeElement) as Boolean
                    ) continue

                    val uuid = getUuid.invoke(storageVolumeElement) as String
                    if (uuid == type) {
                        return File(
                            getPath.invoke(storageVolumeElement).toString() + "/" + split[1]
                        )
                    }
                }

            }
            null
        } else if ("com.android.providers.downloads.documents" == authority) {
            val id = DocumentsContract.getDocumentId(uri)
            if (!TextUtils.isEmpty(id)) {
                val contentUri = ContentUris.withAppendedId(
                    Uri.parse("content://downloads/public_downloads"),
                    java.lang.Long.valueOf(id)
                )
                return getFileFromUri(context, contentUri)
            }
            null
        }
        else if ("com.android.providers.media.documents" == authority) {
            val docId = DocumentsContract.getDocumentId(uri)
            val split = docId.split(":").toTypedArray()
            val type = split[0]
            val contentUri: Uri
            contentUri = if ("image" == type) {
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI
            } else if ("video" == type) {
                MediaStore.Video.Media.EXTERNAL_CONTENT_URI
            } else if ("audio" == type) {
                MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
            } else return null
            val selection = "_id=?"
            val selectionArgs = arrayOf(split[1])
            getFileFromUri(context, contentUri, selection, selectionArgs)
        }
        else if (ContentResolver.SCHEME_CONTENT == scheme)
            getFileFromUri(context, uri)
        else
            null

    }

    return null
}


private fun getFileFromUri(
    context: Context, uri: Uri, selection: String? = null,
    selectionArgs:  kotlin.Array<String>? = null
): File? =
    context.contentResolver.query(uri, arrayOf("_data"), selection, selectionArgs, null)?.let {
        if (it.moveToFirst()) {
            it.getColumnIndex(MediaStore.Images.Media.DATA).let { index->
                if(index == -1 ) null else File(it.getString(index))
            }
        } else null
    }